package orm

import (
	"encoding/json"
	"fmt"
	"gluenet/pkg/apis"
	"gluenet/pkg/meta"
	"gluenet/pkg/ops/dbi"
	"strings"
)

const (
	helmConfigFormat = "resource.helm.config.application.%v"

	queryConfig = "select * from config where label = ?"
)

func ConfigGet(db dbi.GlueDB, mode string, key string, cfgs interface{}) error {
	switch mode {
	case apis.ModuleDefault:
		return db.MetaDB().SQL(queryConfig, key).Find(cfgs)
	case apis.ModuleHelm:
		key = strings.Replace(key, "resource.helm.config.application.", "", -1)
		key = strings.Replace(key, ".", "/", 1)
		if len(key) == 0 {
			return fmt.Errorf("search key is nil")
		}
		c, err := db.HelmCharts(key)
		if err != nil {
			return err
		}
		for _, v := range c {
			bts, _ := json.Marshal(v)
			cfg := meta.Config{
				Label:       fmt.Sprintf(helmConfigFormat, strings.Replace(v.Name, "/", ".", 1)),
				Name:        v.Name,
				Platform:    apis.PlatfromKubernetes,
				ConfigValue: string(bts),
			}
			*cfgs.(*[]meta.Config) = append(*cfgs.(*[]meta.Config), cfg)
		}
		return nil
	default:
		return fmt.Errorf("unknown mods %v, must in %v", mode, apis.Modules())
	}
}

const listConfig = "select * from config where label like 'resource.%v.config.%v%%'"

func listConfigSql(mode string, kind string) string {
	return fmt.Sprintf(listConfig, mode, kind)
}

func ConfigKindListTotal(db dbi.GlueDB, kind string, cfgs *[]meta.Config) error {
	var cfgsDefault []meta.Config
	if err := db.MetaDB().SQL(listConfigSql(apis.ModuleDefault, kind)).Find(&cfgsDefault); err != nil {
		return err
	}
	(*cfgs) = append((*cfgs), cfgsDefault...)
	if kind != apis.KindStrategy {
		c, err := db.HelmCharts("")
		if err != nil {
			return err
		}
		for _, v := range c {
			bts, _ := json.Marshal(v)
			cfg := meta.Config{
				Label:       fmt.Sprintf(helmConfigFormat, strings.Replace(v.Name, "/", ".", 1)),
				Name:        v.Name,
				Platform:    apis.PlatfromKubernetes,
				ConfigValue: string(bts),
			}
			*cfgs = append(*cfgs, cfg)
		}
	}
	return nil
}

func ConfigListTotal(db dbi.GlueDB, cfgs *[]meta.Config) error {
	var appCfgs, strategyCfgs []meta.Config
	if err := ConfigKindListTotal(db, apis.KindApplication, &appCfgs); err != nil {
		return err
	}
	if err := ConfigKindListTotal(db, apis.KindStrategy, &strategyCfgs); err != nil {
		return err
	}
	*cfgs = append(*cfgs, appCfgs...)
	*cfgs = append(*cfgs, strategyCfgs...)
	return nil
}

func ConfigList(db dbi.GlueDB, mode string, kind string, cfgs *[]meta.Config) error {
	switch mode {
	case apis.ModuleDefault:
		return db.MetaDB().SQL(listConfigSql(mode, kind)).Find(cfgs)
	case apis.ModuleHelm:
		if kind == apis.KindStrategy {
			return fmt.Errorf("helm don't have strategy now")
		}
		c, err := db.HelmCharts("")
		if err != nil {
			return err
		}
		for _, v := range c {
			bts, _ := json.Marshal(v)
			cfg := meta.Config{
				Label:       fmt.Sprintf(helmConfigFormat, strings.Replace(v.Name, "/", ".", 1)),
				Name:        v.Name,
				Platform:    apis.PlatfromKubernetes,
				ConfigValue: string(bts),
			}
			*cfgs = append(*cfgs, cfg)
		}
		return nil
	default:
		return fmt.Errorf("unknown mods %v, must in %v", mode, apis.Modules())
	}
}

const queryInstance = "select * from instance where guid = ?"

func InstanceGet(db dbi.GlueDB, key string, ins interface{}) error {
	return db.MetaDB().SQL(queryInstance, key).Find(ins)
}

const queryInstanceRunTime = "select * from instance_runtime where guid = ?"

func InstanceRunTimeGet(db dbi.GlueDB, key string, ins interface{}) error {
	return db.MetaDB().SQL(queryInstanceRunTime, key).Find(ins)
}

func InstanceRunTimeList(db dbi.GlueDB, ins interface{}) error {
	return db.MetaDB().SQL(`select * from instance_runtime`).Find(ins)
}

func InstanceRunTimeContainerTracesGet(db dbi.GlueDB, guid string, ins interface{}) error {
	return db.MetaDB().SQL(`select traces from instance_traces where guid = ?`, guid).Find(ins)
}

const listInstance = "select * from instance where label like 'resource.%v.instance.%v%%'"

func listInstanceSql(typ string, mode string) string {
	return fmt.Sprintf(listInstance, mode, typ)
}

func InstanceList(db dbi.GlueDB, mode string, kind string, ins *[]meta.Instance) error {
	switch mode {
	case apis.ModuleDefault:
		return db.MetaDB().SQL(listInstanceSql(kind, mode)).Find(ins)
	case apis.ModuleHelm:
		return db.MetaDB().SQL(listInstanceSql(kind, mode)).Find(ins)
	case apis.PlatfromGluenets:
		return db.MetaDB().SQL(listInstanceSql(kind, apis.ModuleDefault)).Find(ins)
	case apis.PlatfromKubernetes:
		return db.MetaDB().SQL(listInstanceSql(kind, apis.ModuleHelm)).Find(ins)
	default:
		return fmt.Errorf("unknown mods %v, must in %v", mode, apis.Modules())
	}
}

func InstanceKindList(db dbi.GlueDB, kind string, ins *[]meta.Instance) error {
	var insDefault, insHelm []meta.Instance
	if err := db.MetaDB().SQL(listInstanceSql(kind, apis.ModuleDefault)).Find(&insDefault); err != nil {
		return err
	}
	if err := db.MetaDB().SQL(listInstanceSql(kind, apis.ModuleHelm)).Find(&insHelm); err != nil {
		return err
	}

	(*ins) = append((*ins), insDefault...)
	(*ins) = append((*ins), insHelm...)
	return nil
}

func InstanceListAll(db dbi.GlueDB, ins interface{}) error {
	return db.MetaDB().SQL(`select * from instance`).Find(ins)
}

const queryAgent = "select * from agent where guid = ?"

func AgentGet(db dbi.GlueDB, key string, ins interface{}) error {
	return db.MetaDB().SQL(queryAgent, key).Find(ins)
}

func AgentList(db dbi.GlueDB, ins interface{}) error {
	return db.MetaDB().SQL("select * from agent").Find(ins)
}

const queryScheduleResult = "select * from schedule_result where instances_guid = ?"

func ScheduleResultGet(db dbi.GlueDB, guid string) (*meta.ScheduleResults, error) {
	var result []meta.ScheduleResults
	if err := db.MetaDB().SQL(queryScheduleResult, guid).Find(&result); err != nil {
		return nil, err
	} else {
		if len(result) == 0 {
			return nil, fmt.Errorf("no schedule result")
		}
	}
	return &result[0], nil
}

const queryStrategyLinks = `select * from strategy_links where strategy_guid = ?`

func StrategyLinksGet(db dbi.GlueDB, key string, ins interface{}) error {
	return db.MetaDB().SQL(queryStrategyLinks, key).Find(ins)
}

const queryStrategyUnlink = `select instance.guid from instance, strategy_links where instance.label like "resource.default.instance.application%" and strategy_links.application_guids not like CONCAT("%",instance.guid,"%") and strategy_links.strategy_guid = ?`

func StrategyUnLinksGet(db dbi.GlueDB, key string, ins interface{}) error {
	return db.MetaDB().SQL(queryStrategyUnlink, key).Find(ins)
}

func GetAgentRuntime(db dbi.GlueDB, key string, ins interface{}) error {
	return db.MetaDB().SQL(`select * from agent_runtime where guid = ?`, key).Find(ins)
}

func ListAgentRuntime(db dbi.GlueDB, ins interface{}) error {
	return db.MetaDB().SQL(`select * from agent_runtime`).Find(ins)
}

//func GetInstanceRuntime(impl impl.GlueDB, key string, ins interface{}) error {
//	return impl.MetaDB().SQL(`select * from instance_runtime where guid = ?`, key).Find(ins)
//}

func GetIndexs(c dbi.GlueDB, root string, indexs *[]string) error {
	if err := c.MetaDB().SQL("select indexs from `index` where root = ?", root).Find(indexs); err != nil {
		return err
	}
	return nil
}

//func PromtheusQuery(kind string) error {
//	sql := ""
//	time : time.Now().Unix()
//
//}
